#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "value.h"

typedef struct ValueList
{
    ValuePair pair;
    struct ValueList * next;
} ValueList;

struct Value
{
    enum ValueType type;
    union {
        double number;
        struct {
            size_t len;
            char * buf;
        } str;
        struct {
            ValueList * hash_slot;
            ValueList * array_slot;
        } table;
    };
};

// alloc / free
Value * CreateValue()
{
    Value * val = malloc(sizeof(Value));
    if (val) {
        memset(val, 0, sizeof(Value));
        val->type = VT_NIL;
    }
    return val;
}

void    DestoryValue(Value * val)
{
    if (val) {
        ValueSetNil(val);
        free(val);

    }
}

// cmp
enum ValueType ValueType(Value * val)
{
    if (val == 0) {
        return VT_NIL;
    }
    return val->type;
}

#define MIN(x, y) (((x) < (y))? (x) : (y))
int ValueCmp(Value * v1, Value * v2)
{
	static Value ValueNil;
    ValueNil.type = VT_NIL;

    if (v1 == v2) {
        return 0;
    }


    if (v1 == 0) { v1 = &ValueNil; }
    if (v2 == 0) { v2 = &ValueNil; }

    if (v1->type > v2->type) {
        return 1;
    } else if (v1->type < v2->type) {
        return -1;
    }

    if (v1->type == VT_NUMBER) {
        if (v1->number == v2->number) {
            return 0;
        } else if (v1->number > v2->number) {
            return 1;
        } else {
            return -1;
        }
    } else if (v1->type == VT_STRING) {
        return strncmp(v1->str.buf, v2->str.buf, MIN(v1->str.len, v2->str.len));
    } else {
        if (v1 > v2) {
            return 1;
        } else if (v1 < v2) {
            return -1;
        } else {
            return 0;
        }
    }
}

// init
Value * NilValue()
{
    return CreateValue();
}

Value * NumberValue(double val)
{
    return ValueSetNumber(CreateValue(), val);
}

Value * StringValue   (const char * str, int len)
{
    return ValueSetString(CreateValue(), str, len);
}

Value * ValueFromValue(Value * val)
{
    return ValueSet(CreateValue(), val);
}

// set
Value * ValueSetNil(Value * val) 
{
    if (val == 0) { return 0; }

    if (val->type == VT_STRING) {
        if (val->str.buf) {
            free(val->str.buf);
            val->str.buf = 0;
            val->str.len = 0;
        }
    } else if (val->type == VT_TABLE) {
        while(val->table.hash_slot) {
            ValueList * c = val->table.hash_slot;
            val->table.hash_slot = c->next;
            DestoryValue(c->pair.key);
            DestoryValue(c->pair.val);
            free(c);
        }

        while(val->table.array_slot) {
            ValueList * c = val->table.array_slot;
            val->table.array_slot = c->next;
            DestoryValue(c->pair.key);
            DestoryValue(c->pair.val);
            free(c);
        }
    }
    return val;
}

Value * ValueSetNumber(Value * val, double f)
{
    if (val) {
        ValueSetNil(val);
        val->type = VT_NUMBER;
        val->number = f;
    }
    return val;
}

Value * ValueSetString(Value * val, const char * str, size_t len)
{
    if (val) {
        ValueSetNil(val);
        if (str == 0) { return val; }
        if (len < 0) { len = strlen(str); }

        val->type = VT_STRING;
        val->str.len = len + 1;
        val->str.buf = malloc(val->str.len);
        if (len > 0) {
            memcpy(val->str.buf, str, len);
        }
        val->str.buf[len] = 0;
    }
    return val;
}

//Value * ValueSetKV    (Value * tval, Value * key, Value * val);
static ValueList * ValueListRemove(ValueList * slot, Value * key)
{
	ValueList * newHead = slot;
    ValueList * prev = 0; 
    ValueList * ite = slot; 
 

    if (key == 0) {
        return slot;
    }

    while (ite && ValueCmp(ite->pair.key, key) < 0) { 
        prev = ite; 
        ite = ite->next; 
    }

    if (ite && ValueCmp(ite->pair.key, key) == 0) {
        if (prev == 0) {
            newHead = ite->next;
        } else {
            prev->next = ite->next;
        }
        DestoryValue(ite->pair.key);
        DestoryValue(ite->pair.val);
        free(ite);
    }
    return newHead;
}

static ValueList * ValueListInsert(ValueList * slot, Value * key, Value * val) 
{
	ValueList * newHead = slot;
    ValueList * prev = 0; 
    ValueList * ite = slot; 

    if (key == 0) {
        return slot;
    }


    while (ite && ValueCmp(ite->pair.key, key) < 0) { 
        prev = ite; 
        ite = ite->next; 
    }

    if (ite && ValueCmp(ite->pair.key, key) == 0) {
        ite->pair.val = val; //ValueFromValue(val);
        DestoryValue(key);
    } else {
        ValueList * ns = malloc(sizeof(ValueList)); 
        ns->pair.key = key; //ValueFromValue(key); 
        ns->pair.val = val; //ValueFromValue(val);
        ns->next = 0; 
        if (prev == 0) { 
            ns->next = slot; 
            newHead = ns; 
        } else { 
            ns->next = prev->next; 
            prev->next = ns; 
        } 
    }
    return newHead;
}

Value * ValueSetSV(Value * table, const char * key, Value * val)
{
    if (table == 0) { return table; }


    if (val == 0 || val->type == VT_NIL) {
        Value v;
        v.type = VT_STRING;
        v.str.buf = (char*)key;
        v.str.len = strlen(key) + 1;
        table->table.hash_slot = ValueListRemove(table->table.hash_slot, &v);
    } else {
        table->table.hash_slot = ValueListInsert(table->table.hash_slot, StringValue(key, -1), val);
    }
    return table;
}

Value * ValueSetIV(Value * table, int key, Value * val)
{
    if (table == 0) { return table; }

    if (val == 0 || val->type == VT_NIL) {
        Value v;
        v.type = VT_NUMBER;
        v.number = key;
        table->table.array_slot = ValueListRemove(table->table.array_slot, &v);
    } else {
        table->table.array_slot = ValueListInsert(table->table.array_slot, NumberValue(key), val);
    }
    return table;
}

Value * ValueSetKV(Value * table, Value * key, Value * val)
{
    if (table == 0) {
        return table;
    }

    if (table->type != VT_TABLE) {
        ValueSetNil(table);
        table->type = VT_TABLE;
    }

    if (val == 0 || val->type == VT_NIL) {
        if (key->type == VT_NUMBER) {
            table->table.array_slot = ValueListRemove(table->table.array_slot, key);
        } else if (key->type == VT_STRING) {
            table->table.hash_slot = ValueListRemove(table->table.hash_slot, key);
        } 
    } else {
        if (key->type == VT_NUMBER) {
            table->table.array_slot = ValueListInsert(table->table.array_slot, key, val);
        } else if (key->type == VT_STRING) {
            table->table.hash_slot = ValueListInsert(table->table.hash_slot, key, val);
        } 
    }
    return table;
}

Value * ValueSet(Value * dv, Value * sv)
{
    if (dv == 0) { return 0; }

    ValueSetNil(dv);
    if (sv == 0 || sv->type == VT_NIL) {
        return dv;
    }

    if (sv->type == VT_NUMBER) {
        ValueSetNumber(dv, sv->number);
    } else if (sv->type == VT_STRING) {
        ValueSetString(dv, sv->str.buf, sv->str.len - 1);
    } else if (sv->type == VT_TABLE) {
        ValueList * ite = sv->table.hash_slot; 
        while (ite) {
            ValueSetKV(dv, ite->pair.key, ite->pair.val);
            ite = ite->next;
        }

        ite = sv->table.array_slot; 
        while (ite) {
            ValueSetKV(dv, ite->pair.key, ite->pair.val);
            ite = ite->next;
        }
    }
    return dv;
}

// get
double ValueToNumber(Value * val)
{
    double ret = 0;
    if (val->type == VT_NUMBER) {
        ret = val->number;
    } else if (val->type == VT_STRING) {
        ret = atof(val->str.buf);
    } 
    return ret;
}

int ValueToInterger(Value * val)
{
    return (int)ValueToNumber(val);
}

const char * ValueToString(Value * val, size_t * len)
{
    const char * ret = 0;
    if (val->type == VT_NUMBER) {
        static char buffer[256] = {0};
        sprintf(buffer, "%f", val->number);
        ret = buffer;
        if (len) *len = strlen(buffer);
    } else if (val->type == VT_STRING) {
        ret = val->str.buf;
        if (len)  *len = val->str.len - 1;
    } 
    return ret;
}

// get table
int TableValueHashCount(Value * table)
{
	int cnt = 0;
	ValueList * ite;
    if (table == 0) {
        return 0;
    }

    ite = table->table.hash_slot;
    while (ite) {
        cnt ++;
        ite = ite->next;
    }
    return cnt;
}

int TableValueArrayMaxIndex(Value * table)
{	
	int cnt = 0;
    ValueList * ite;
    if (table == 0) {
        return 0;
    }

    ite = table->table.array_slot;
    while (ite) {
        if (cnt < ite->pair.key->number) {
            cnt = (int)ite->pair.key->number;
        }
        ite = ite->next;
    }
    return cnt;
}

ValuePair * TableValueHashNext(Value * table, ValuePair * cur)
{
	ValueList * l = (ValueList*)cur;

    if (table == 0) { return 0; }

    if (cur == 0) {
        if (table->table.hash_slot) {
            return &(table->table.hash_slot->pair);
        } else {
            return 0;
        }
    }


    if (l->next) {
        return &(l->next->pair);
    } else {
        if (cur->key->type == VT_NUMBER) {
            return &(table->table.hash_slot->pair);
        }
        return 0;
    }

}

#if 0
ValuePair * TableValueNext(Value * table, ValuePair * cur)
{
    if (table == 0) { return 0; }

    if (cur == 0) {
        if (table->table.array_slot) {
            return &(table->table.array_slot->pair);
        } else {
            return &(table->table.hash_slot->pair);
        }
    }

    ValueList * l = (ValueList*)cur;
    if (l->next) {
        return &(l->next->pair);
    } else {
        if (cur->key->type == VT_NUMBER) {
            return &(table->table.hash_slot->pair);
        }
        return 0;
    }
}
#endif

Value * TableValueByName (Value * tval, const char * key)
{
	size_t key_len;
    ValueList * ite;
	if (key == 0 || tval == 0 || tval->type != VT_TABLE) {
        return 0;
    }

    key_len = strlen(key) + 1;

    ite = tval->table.hash_slot;
    while (ite) {
        if (ite->pair.key->str.len != key_len) {
            continue;
        }
        if (memcmp(ite->pair.key->str.buf, key, key_len) == 0) {
            return ite->pair.val;
        }
        ite = ite->next;
    }
    return 0;

}

Value * TableValueAtIndex(Value * tval, int i)
{
	ValueList * ite;
    if (tval == 0 || tval->type != VT_TABLE) {
        return 0;
    }

    ite = tval->table.array_slot;
    while (ite) {
        if ((int)(ite->pair.key->number) == i) {
            return ite->pair.val;
        }
        ite = ite->next;
    }
    return 0;
}

Value * TableValueOf(Value * tval, Value * key)
{
    if (key->type == VT_NUMBER) {
        return TableValueAtIndex(tval, key->number);
    } else if (key->type == VT_STRING) {
        return TableValueByName(tval, key->str.buf);
    }
    return 0;
}


#ifdef _TEST
int main(int argc, char * argv[])
{
    return 0;
}
#endif
